﻿/*
* 创建者：LIYINFAI
* 创建时间：2023/10/24 9:35:26
* 描述：
* --------------------------------------
* 修改说明：
* --------------------------------------
*/
using CommonLibrary.Forms;
using Newtonsoft.Json;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;

namespace CommonLibrary
{
    /// <summary>
    /// 删除文件扩展类
    /// </summary>
    public static class DeleteFileClass
    {
        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="file"></param>
        public static void DeleteFile(this FileInfo file)
        {
            try
            {
                if (file.Exists)
                {
                    file.Attributes = FileAttributes.Normal;
                    file.Delete();
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }
    }
    /// <summary>
    /// 除法属性
    /// </summary>
    public class DivisionAttribute : Attribute
    {
        /// <summary>
        /// 除以多少，默认除以 1
        /// </summary>
        public float DivValue { get; set; } = 1.0f;
        /// <summary>
        /// 字符串输出格式，默认 F2
        /// </summary>
        public string FormatValue { get; set; } = "F2";
    }
    /// <summary>
    /// 显示于某控件列的长度属性定义
    /// </summary>
    public class GUIColumnWidthAttribute : Attribute
    {
        /// <summary>
        /// 宽度
        /// </summary>
        public int Width { get; set; } = 220;
    }
    /// <summary>
    /// 名称描述
    /// </summary>
    public class CNameDesc
    {
        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 描述
        /// </summary>
        public string Description { get; set; }
    }
    /// <summary>
    /// 公共操作类
    /// </summary>
    public class CommonHelper
    {
        /// <summary>
        /// 整体编码方式
        /// </summary>
        public static readonly Encoding ENCODING = new UTF8Encoding(false);
        private static char[] ZERO_START_ARRAY = new char[] { '0' };
        private static char[] SplitParameterArray = new char[] { ';', '|' };
        private static char[] SplitValueArray = new char[] { ':', '：' };
        private static char[] CSVSplitValueArray = new char[] { ',' };
        private static char[] EMPTY_END_CHAR_ARRAY = new char[] { '\0', '\u0000' };
        private static Regex SPECIAL_REGEX = new Regex("[\u0000,\u0001,\u0002,\u0003,\u0004,\u0005,\u0006,\u0007,\u0008,\u0009,\u000A,\u000B,\u000C,\u000D,\u000E,\u000F,\u0010,\u0011,\u0012,\u0013,\u0014,\u0015,\u0016,\u0017,\u0018,\u0019,\u001A,\u001B,\u001C,\u001D,\u001E,\u001F,\0]");
        /// <summary>
        /// 配置文件统一目录
        /// </summary>
        public static string COMMON_CONFIG_DIR => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Configs");
        private static HWFrmWaiting FORM_WAITING = null;
        private static object WAITING_LOCK = new object();
        /// <summary>
        /// 显示等待信息
        /// </summary>
        /// <param name="win"></param>
        /// <param name="message"></param>
        public static void ShowWaiting(HWFrmBase win, string message)
        {
            lock (WAITING_LOCK)
            {
                if (FORM_WAITING == null)
                {
                    FORM_WAITING = new HWFrmWaiting();
                    System.Threading.Thread thread = new System.Threading.Thread(ShowWaitingForm);
                    thread.IsBackground = true;
                    thread.SetApartmentState(System.Threading.ApartmentState.STA);
                    thread.Start(new WaitingEntity() { Win = win, Message = message });
                }
                else
                {
                    FORM_WAITING.UpdateMessage(message);
                }
            }
        }
        /// <summary>
        /// 关闭等待窗口
        /// </summary>
        public static void CloseWaiting()
        {
            Thread.Sleep(20);
            if (FORM_WAITING != null && FORM_WAITING.Created)
            {
                if (FORM_WAITING.InvokeRequired)
                {
                    FORM_WAITING.Invoke(new Action(() =>
                    {
                        CloseWaiting();
                    }));
                }
                else
                {
                    try
                    {
                        FORM_WAITING.Close();
                        FORM_WAITING.Dispose();
                        FORM_WAITING = null;
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Error(ex);
                    }
                }
            }
        }
        private static void ShowWaitingForm(object waiting)
        {
            if (FORM_WAITING != null && FORM_WAITING.Created)
            {
                CloseWaiting();
            }
            if (waiting != null && waiting is WaitingEntity)
            {
                FORM_WAITING.WaitingMessage = $"{(waiting as WaitingEntity).Message}";
                HWFrmBase win = (waiting as WaitingEntity).Win;
                FORM_WAITING.UpdateSize(win);
            }
            FORM_WAITING.ShowDialog();
        }
        /// <summary>
        /// 初始化DataGridView
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataGridView"></param>
        /// <param name="frozenColumns"></param>
        /// <param name="needIdColumn"></param>
        /// <param name="ignoreColumns"></param>
        public static void InitDataGridViewColumns<T>(DataGridView dataGridView, string[] frozenColumns = null, bool needIdColumn = true, string[] ignoreColumns = null)
            where T : new()
        {
            dataGridView.ColumnHeadersDefaultCellStyle.Font = new Font("微软雅黑", 12, FontStyle.Bold);
            dataGridView.Rows.Clear();
            dataGridView.Columns.Clear();
            if (needIdColumn)
            {
                DataGridViewTextBoxColumn idColumn = new DataGridViewTextBoxColumn();
                bool isFrozen = frozenColumns != null && (frozenColumns.Contains("id") || frozenColumns.Contains("Id"));
                InitTextGridColumn(idColumn, "id", "序号", isFrozen);
                idColumn.Width = 80;
                dataGridView.Columns.Add(idColumn);
            }
            T productInfo = new T();
            System.Reflection.PropertyInfo[] properties = productInfo.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
            foreach (System.Reflection.PropertyInfo item in properties)
            {
                DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();
                object[] proDescription = item.GetCustomAttributes(typeof(DescriptionAttribute), true);
                bool isFrozen = frozenColumns != null && frozenColumns.Contains(item.Name);
                InitTextGridColumn(column, item.Name, proDescription != null && proDescription.Length > 0 ? ((DescriptionAttribute)proDescription[0]).Description : item.Name, isFrozen);
                if (!item.Name.ToLower().Equals("id") && proDescription != null && proDescription.Length > 0 && (ignoreColumns == null || ignoreColumns.Length == 0 || !ignoreColumns.Contains(item.Name)))
                {
                    object[] colWidthDescription = item.GetCustomAttributes(typeof(GUIColumnWidthAttribute), true);
                    if (colWidthDescription != null && colWidthDescription.Length > 0)
                    {
                        column.Width = (colWidthDescription[0] as GUIColumnWidthAttribute).Width;
                    }
                    else
                    {
                        column.Width = column.HeaderText.Length < 5 ? 125 : column.HeaderText.Length * 25;
                    }
                    dataGridView.Columns.Add(column);
                }
            }
            dataGridView.DoubleBufferedDataGirdView(true);
            dataGridView.InitStyle();
        }
        /// <summary>
        /// 从记录行中转换实体对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="row"></param>
        /// <param name="obj"></param>
        public static void ObjFromDataRow<T>(DataRow row, T obj)
        {
            var propertyInfos = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var p in propertyInfos)
            {
                string name = p.Name;
                if (row.Table.Columns.Contains(name))
                {
                    var cellValue = row[name];
                    if (cellValue != null && cellValue != DBNull.Value && p.CanWrite)
                    {
                        switch (p.PropertyType.Name)
                        {
                            case "String": p.SetValue(obj, cellValue.ToString()); break;
                            case "Int16": p.SetValue(obj, Int16.Parse(cellValue.ToString())); break;
                            case "Int32": p.SetValue(obj, Int32.Parse(cellValue.ToString())); break;
                            case "Int64": p.SetValue(obj, Int64.Parse(cellValue.ToString())); break;
                            case "UInt16": p.SetValue(obj, UInt16.Parse(cellValue.ToString())); break;
                            case "UInt32": p.SetValue(obj, UInt32.Parse(cellValue.ToString())); break;
                            case "UInt64": p.SetValue(obj, UInt64.Parse(cellValue.ToString())); break;
                            case "Single": p.SetValue(obj, float.Parse(cellValue.ToString())); break;
                            case "Double": p.SetValue(obj, double.Parse(cellValue.ToString())); break;
                            case "Decimal": p.SetValue(obj, float.Parse(cellValue.ToString())); break;
                            case "byte": p.SetValue(obj, cellValue.ToString()); break;
                            case "Boolean": p.SetValue(obj, cellValue.ToString().ToUpper() == "TRUE" || cellValue.ToString() == "1" ? 1 : 0); break;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 从数据表中转换对象列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="table"></param>
        /// <returns></returns>
        public static List<T> ObjFromDataTable<T>(DataTable table)
        where T : new()
        {
            List<T> list = new List<T>();
            if (table != null && table.Rows.Count > 0)
            {
                foreach (DataRow row in table.Rows)
                {
                    T obj = new T();
                    ObjFromDataRow(row, obj);
                    list.Add(obj);
                }
            }
            return list;
        }
        /// <summary>
        /// 获取单元格值
        /// </summary>
        /// <param name="row"></param>
        /// <param name="columnName"></param>
        /// <returns></returns>
        public static string GetCellStringValue(DataGridViewRow row, string columnName)
        {
            string result = string.Empty;
            if (row != null && !string.IsNullOrWhiteSpace(columnName.Trim()) && row.DataGridView.Columns.Contains(columnName))
            {
                var cell = row.Cells[columnName].Value;
                result = cell == null ? result : cell.ToString().Trim();
            }
            return result;
        }
        /// <summary>
        /// 检查是否能连上
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public static bool CheckConnect(string ip, int port)
        {
            bool result = false;
            try
            {
                var s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                s.ConnectAsync(ip, port).Wait(100);
                result = s.Connected;
                s.Close();
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
                result = false;
            }
            return result;
        }
        /// <summary>
        /// 清理Socket缓存
        /// </summary>
        /// <param name="socket"></param>
        public static void ClearSocketCache(Socket socket)
        {
            if (socket != null && socket.Connected)
            {
                int i = 0;
                socket.ReceiveTimeout = 10;
                byte[] buffer = new byte[256];
                while (i < 2)
                {
                    try
                    {
                        int len = socket.Receive(buffer);
                        break;
                    }
                    catch
                    {
                    }
                    i++;
                }
            }
        }
        /// <summary>
        /// 去除特殊字符
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string ReplaceString(string value)
        {
            string result = string.Empty;
            if (!string.IsNullOrWhiteSpace(value))
            {
                result = SPECIAL_REGEX.Replace(value, "");
            }
            return result;
        }
        /// <summary>
        /// 初始化文本列
        /// </summary>
        /// <param name="column"></param>
        /// <param name="name"></param>
        /// <param name="headerText"></param>
        /// <param name="isFrozen"></param>
        public static void InitTextGridColumn(DataGridViewColumn column, string name, string headerText, bool isFrozen = false)
        {
            column.Name = name;
            column.HeaderText = headerText;
            column.Frozen = isFrozen;
            column.DefaultCellStyle.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
        }
        /// <summary>
        /// 创建文本列
        /// </summary>
        /// <param name="dataGridView"></param>
        /// <param name="name"></param>
        /// <param name="headerText"></param>
        /// <param name="alignment"></param>
        /// <param name="width"></param>
        /// <param name="isFill"></param>
        /// <param name="isReadOnly"></param>
        /// <returns></returns>
        public static DataGridViewTextBoxColumn CreateTextGridColumn(DataGridView dataGridView, string name, string headerText, DataGridViewContentAlignment alignment = DataGridViewContentAlignment.MiddleCenter
            , int width = 120, bool isFill = false, bool isReadOnly = false)
        {
            DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();
            column.Name = name;
            column.HeaderText = headerText;
            column.DefaultCellStyle.Alignment = alignment;
            column.Width = width;
            column.ReadOnly = isReadOnly;
            if (isFill)
            {
                column.FillWeight = 100;
            }
            dataGridView.Columns.Add(column);
            return column;
        }
        /// <summary>
        /// 创建下拉框列
        /// </summary>
        /// <param name="dataGridView"></param>
        /// <param name="name"></param>
        /// <param name="headerText"></param>
        /// <param name="options"></param>
        /// <param name="alignment"></param>
        /// <param name="width"></param>
        /// <param name="isFill"></param>
        /// <returns></returns>
        public static DataGridViewComboBoxColumn CreateComboGridColumn(DataGridView dataGridView, string name, string headerText,
            string[] options,
            DataGridViewContentAlignment alignment = DataGridViewContentAlignment.MiddleCenter
            , int width = 120, bool isFill = false)
        {
            DataGridViewComboBoxColumn column = new DataGridViewComboBoxColumn();
            column.Name = name;
            column.HeaderText = headerText;
            column.DefaultCellStyle.Alignment = alignment;
            column.Width = width;
            column.Items.AddRange(options);
            if (isFill)
            {
                column.FillWeight = 100;
            }
            dataGridView.Columns.Add(column);
            return column;
        }
        /// <summary>
        /// 初始化Checkbox列
        /// </summary>
        /// <param name="column"></param>
        /// <param name="name"></param>
        /// <param name="headerText"></param>
        public static void InitCheckboxGridColumn(DataGridViewCheckBoxColumn column, string name, string headerText)
        {
            column.Name = name;
            column.HeaderText = headerText;
            column.DefaultCellStyle.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
        }
        /// <summary>
        /// 初始化下拉列
        /// </summary>
        /// <param name="column"></param>
        /// <param name="name"></param>
        /// <param name="headerText"></param>
        /// <param name="values"></param>
        public static void InitComboGridColumn(DataGridViewComboBoxColumn column, string name, string headerText, string[] values)
        {
            column.Name = name;
            column.HeaderText = headerText;
            column.DataSource = values;
            column.DefaultCellStyle.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
        }
        /// <summary>
        /// 获取数据存放目录
        /// </summary>
        /// <returns></returns>
        public static string GetBaseDataDirectory()
        {
            return GetConfiguration("DataDir", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AppDatas"));
        }
        /// <summary>
        /// 获取程序中某个配置值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static string GetConfiguration(string key, string defaultValue)
        {
            if (!string.IsNullOrWhiteSpace(key) && ConfigurationManager.AppSettings.AllKeys.Contains(key))
            {
                return ConfigurationManager.AppSettings[key];
            }
            else
                return defaultValue;
        }
        /// <summary>
        /// 获取JSON字符串
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="formatting"></param>
        /// <returns></returns>
        public static string GetJsonString(object obj, Formatting formatting = Formatting.Indented)
        {
            string result = string.Empty;
            if (obj != null)
            {
                result = JsonConvert.SerializeObject(obj, formatting);
            }
            return result;
        }
        /// <summary>
        /// 将JSON字符串转化为对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jsonString"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static T GetJson<T>(string jsonString, T defaultValue)
        {
            T result = defaultValue;
            if (!string.IsNullOrWhiteSpace(jsonString))
            {
                try
                {
                    result = JsonConvert.DeserializeObject<T>(jsonString);
                }
                catch (Exception ex)
                {
                    result = defaultValue;
                    LogHelper.Error(ex);
                }
            }
            return result;
        }
        /// <summary>
        /// 获取对象所有属性信息
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static List<PropertyInfo> GetObjectProperties(object obj)
        {
            return obj.GetType().GetProperties().ToList();
        }
        /// <summary>
        /// 把DataGridView的记录写入DataTable
        /// </summary>
        /// <param name="dataGridView"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public static DataTable GetDataTable(DataGridView dataGridView, string tableName = "Scan")
        {
            DataTable table = new DataTable(tableName);
            foreach (DataGridViewColumn c in dataGridView.Columns)
            {
                table.Columns.Add(c.Name);
            }
            foreach (DataGridViewRow r in dataGridView.Rows)
            {
                bool isValid = true;
                var row = table.NewRow();
                bool isFirst = true;
                foreach (DataGridViewColumn c in dataGridView.Columns)
                {
                    if (null == r.Cells[c.Name].Value && isFirst)
                    {
                        isValid = false;
                        break;
                    }
                    row[c.Name] = r.Cells[c.Name].Value;
                    isFirst = false;
                }
                if (isValid)
                    table.Rows.Add(row);
            }
            return table;
        }
        /// <summary>
        /// 返回对象的属性列表
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="ignoreNonDescription"></param>
        /// <returns></returns>
        public static (Dictionary<string, string> dic, List<PropertyInfo> pList) GetCSVHeader(object obj, bool ignoreNonDescription = false)
        {
            var result = (dic: new Dictionary<string, string>(), pList: new List<PropertyInfo>());
            var propertyInfos = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            for (var i = 0; i < propertyInfos.Length; i++)
            {
                var p = propertyInfos[i];
                var name = p.Name;
                var title = p.Name;
                var desc = p.GetCustomAttribute(typeof(DescriptionAttribute));
                if (null != desc)
                {
                    title = ((DescriptionAttribute)desc).Description;
                }
                if (!ignoreNonDescription || (ignoreNonDescription && null != desc))
                {
                    result.dic.Add(name, title);
                    result.pList.Add(p);
                }
            }
            return result;
        }
        /// <summary>
        /// 11 加粗 样式
        /// </summary>
        /// <param name="workbook"></param>
        /// <returns></returns>
        private static ICellStyle GetBoldStyle(IWorkbook workbook)
        {
            IFont font = workbook.CreateFont();
            font.IsBold = true;
            font.FontHeightInPoints = 11;
            ICellStyle boldStyle = workbook.CreateCellStyle();
            boldStyle.FillPattern = FillPattern.SolidForeground;
            boldStyle.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Grey25Percent.Index;
            boldStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
            boldStyle.VerticalAlignment = VerticalAlignment.Center;
            boldStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;
            boldStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;
            boldStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;
            boldStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;
            boldStyle.SetFont(font);
            boldStyle.WrapText = true;
            return boldStyle;
        }
        /// <summary>
        /// 红色背景 样式
        /// </summary>
        /// <param name="workbook"></param>
        /// <returns></returns>
        private static ICellStyle GetRedBackNormalStyle(IWorkbook workbook)
        {
            IFont font = workbook.CreateFont();
            font.FontHeightInPoints = 11;
            ICellStyle normalStyle = workbook.CreateCellStyle();
            normalStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
            normalStyle.VerticalAlignment = VerticalAlignment.Center;
            normalStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;
            normalStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;
            normalStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;
            normalStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;
            normalStyle.FillPattern = FillPattern.SolidForeground;
            normalStyle.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Red.Index;
            normalStyle.SetFont(font);
            normalStyle.WrapText = true;
            return normalStyle;
        }
        /// <summary>
        /// 红色字体 样式
        /// </summary>
        /// <param name="workbook"></param>
        /// <returns></returns>
        private static ICellStyle GetRedNormalStyle(IWorkbook workbook)
        {
            IFont font = workbook.CreateFont();
            font.Color = IndexedColors.Red.Index;
            font.FontHeightInPoints = 11;
            ICellStyle normalStyle = workbook.CreateCellStyle();
            normalStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
            normalStyle.VerticalAlignment = VerticalAlignment.Center;
            normalStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;
            normalStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;
            normalStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;
            normalStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;
            normalStyle.SetFont(font);
            normalStyle.WrapText = true;
            return normalStyle;
        }
        /// <summary>
        /// 常规 样式
        /// </summary>
        /// <param name="workbook"></param>
        /// <returns></returns>
        private static ICellStyle GetNormalStyle(IWorkbook workbook)
        {
            IFont font = workbook.CreateFont();
            font.FontHeightInPoints = 11;
            ICellStyle normalStyle = workbook.CreateCellStyle();
            normalStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
            normalStyle.VerticalAlignment = VerticalAlignment.Center;
            normalStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;
            normalStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;
            normalStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;
            normalStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;
            normalStyle.SetFont(font);
            normalStyle.WrapText = true;
            return normalStyle;
        }
        /// <summary>
        /// 数字 样式
        /// </summary>
        /// <param name="workbook"></param>
        /// <returns></returns>
        private static ICellStyle GetIntStyle(IWorkbook workbook)
        {
            IFont font = workbook.CreateFont();
            font.FontHeightInPoints = 11;
            ICellStyle intStyle = workbook.CreateCellStyle();
            intStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
            intStyle.VerticalAlignment = VerticalAlignment.Center;
            intStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;
            intStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;
            intStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;
            intStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;
            intStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("0");
            intStyle.SetFont(font);
            intStyle.WrapText = true;
            return intStyle;
        }
        /// <summary>
        /// 浮点数 样式
        /// </summary>
        /// <param name="workbook"></param>
        /// <returns></returns>
        private static ICellStyle GetFloatStyle(IWorkbook workbook)
        {
            IFont font = workbook.CreateFont();
            font.FontHeightInPoints = 11;
            ICellStyle floatStyle = workbook.CreateCellStyle();
            floatStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
            floatStyle.VerticalAlignment = VerticalAlignment.Center;
            floatStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;
            floatStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;
            floatStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;
            floatStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;
            floatStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("0.00");
            floatStyle.SetFont(font);
            floatStyle.WrapText = true;
            return floatStyle;
        }
        /// <summary>
        /// 创建一个新的Excel文件
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="headers"></param>
        /// <param name="sheetName"></param>
        public static void NewExcelFile(string filePath, List<string> headers, string sheetName)
        {
            IWorkbook workbook = new XSSFWorkbook();
            ISheet sheet = workbook.CreateSheet(sheetName);
            if (headers != null && headers.Count > 0)
            {
                IRow row = sheet.CreateRow(0);
                int columnIndex = 0;
                foreach (var key in headers)
                {
                    NPOI.SS.UserModel.ICell cell = row.CreateCell(columnIndex++);
                    cell.SetCellValue(key);
                    cell.CellStyle = GetBoldStyle(workbook);
                }
            }
            using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
            {
                workbook.Write(stream);
                workbook.Close();
                workbook = null;
            }
        }
        /// <summary>
        /// 把整个DataGridView显示的内容导出到Excel中
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="dataGridView"></param>
        /// <param name="overwrite"></param>
        /// <param name="sheetName"></param>
        public static void DataGridViewToExcel(string filePath, DataGridView dataGridView, bool overwrite = false, string sheetName = "数据")
        {
            if (dataGridView.Rows != null && dataGridView.Rows.Count > 0)
            {
                List<string> headers = new List<string>();
                foreach (DataGridViewColumn c in dataGridView.Columns)
                {
                    if (c.Visible)
                    {
                        headers.Add(c.HeaderText);
                    }
                }
                FileStream fs = null;
                IWorkbook workbook = null;
                try
                {
                    bool isNewFile = CheckFile(filePath);
                    if (isNewFile)
                    {
                        NewExcelFile(filePath, headers, sheetName);
                    }
                    fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    workbook = new XSSFWorkbook(fs);
                    ISheet sheet = workbook.GetSheetAt(0);
                    int lastRowNum = sheet.LastRowNum;
                    ICellStyle titleStyle = GetBoldStyle(workbook);
                    ICellStyle normalStyle = GetNormalStyle(workbook);
                    ICellStyle redNormalStyle = GetRedNormalStyle(workbook);
                    ICellStyle redBackNormalStyle = GetRedBackNormalStyle(workbook);
                    ICellStyle intStyle = GetIntStyle(workbook);
                    if (overwrite && !isNewFile)
                    {
                        workbook.RemoveSheetAt(0);
                        sheet = workbook.CreateSheet(sheetName);
                        if (headers != null && headers.Count > 0)
                        {
                            IRow row = sheet.CreateRow(0);
                            int columnIndex = 0;
                            foreach (var key in headers)
                            {
                                NPOI.SS.UserModel.ICell cell = row.CreateCell(columnIndex++);
                                cell.SetCellValue(key);
                                cell.CellStyle = titleStyle;
                            }
                        }
                        lastRowNum = 0;
                    }
                    int rowIndex = lastRowNum + 1;
                    foreach (DataGridViewRow rowData in dataGridView.Rows)
                    {
                        int columnIndex = 0;
                        IRow row = sheet.CreateRow(rowIndex++);
                        foreach (DataGridViewColumn col in dataGridView.Columns)
                        {
                            if (col.Visible)
                            {
                                DataGridViewCell cellData = rowData.Cells[col.Name];
                                string cellValue = "";
                                if (cellData != null && cellData.Value != DBNull.Value && cellData.Value != null)
                                {
                                    cellValue = cellData.Value.ToString();
                                }
                                ICellStyle cellStyle = cellData.Style.BackColor == Color.Red ? redBackNormalStyle : (cellData.Style.ForeColor == Color.Red ? redNormalStyle : normalStyle);

                                NPOI.SS.UserModel.ICell cell = row.CreateCell(columnIndex++);
                                cell.CellStyle = cellStyle;
                                cell.SetCellValue(cellValue);
                            }
                        }
                    }
                    using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                    {
                        workbook.Write(stream);
                    }
                    workbook.Close();
                    workbook = null;
                    fs.Close();
                    fs = null;
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
                finally
                {
                    if (workbook != null)
                    {
                        try
                        {
                            workbook.Close();
                        }
                        catch (Exception ex1)
                        {
                            LogHelper.Error(ex1);
                        }
                    }
                    if (fs != null)
                    {
                        try
                        {
                            fs.Close();
                        }
                        catch (Exception ex2)
                        {
                            LogHelper.Error(ex2);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 显示进度信息代理
        /// </summary>
        /// <param name="message"></param>
        public delegate void ShowInfoDelagete(string message);
        /// <summary>
        /// 生成Excel
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filePath">文件路径</param>
        /// <param name="objList">数据</param>
        /// <param name="overwrite">是否重写</param>
        /// <param name="sheetName">表名称</param>
        /// <param name="showInfoDelagete">显示消息代理</param>
        /// <param name="ignoreNonDescription"></param>
        /// <param name="needRebuildId">是否需要重塑ID</param>
        /// <param name="otherHideColumns">需要隐藏的列名</param>
        /// <param name="IsTranEnumRealValue">是否需要将枚举值转为真实值</param>
        /// <returns></returns>
        public static bool WriteExcel<T>(string filePath, List<T> objList, bool overwrite = false, string sheetName = "数据",
            ShowInfoDelagete showInfoDelagete = null, bool ignoreNonDescription = true,
            bool needRebuildId = true, string[] otherHideColumns = null, bool IsTranEnumRealValue = false)
        {
            bool result = false;
            if (objList != null && objList.Count > 0)
            {
                object obj = objList[0];
                FileStream fs = null;
                IWorkbook workbook = null;
                try
                {
                    var headAndPty = GetCSVHeader(obj, ignoreNonDescription);
                    Dictionary<string, string> headers = headAndPty.dic;
                    if (otherHideColumns != null)
                    {
                        foreach (string col in otherHideColumns)
                        {
                            if (headers.ContainsKey(col))
                            {
                                headers.Remove(col);
                            }
                        }
                    }
                    bool isNewFile = CheckFile(filePath);
                    if (isNewFile)
                    {
                        NewExcelFile(filePath, headers.Values.ToList(), sheetName);
                    }
                    fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    workbook = new XSSFWorkbook(fs);
                    //获取表的位置
                    int sIndex = workbook.GetSheetIndex(sheetName);
                    ISheet sheet;
                    //-1则为空
                    if (sIndex == -1)
                    {
                        //创建新表
                        sheet = workbook.CreateSheet(sheetName);
                        //更新表位置索引
                        sIndex = workbook.GetSheetIndex(sheetName);
                    }
                    else
                    {
                        //按位置获取表
                        sheet = workbook.GetSheetAt(sIndex);
                    }
                    int lastRowNum = sheet.LastRowNum;
                    List<PropertyInfo> pList = headAndPty.pList;
                    ICellStyle titleStyle = GetBoldStyle(workbook);
                    ICellStyle normalStyle = GetNormalStyle(workbook);
                    ICellStyle redNormalStyle = GetRedNormalStyle(workbook);
                    ICellStyle intStyle = GetIntStyle(workbook);
                    var columnWidths = new Dictionary<string, int>();
                    if (overwrite || isNewFile)
                    {
                        workbook.RemoveSheetAt(sIndex);
                        sheet = workbook.CreateSheet(sheetName);
                        if (headers != null && headers.Keys.Count > 0)
                        {
                            IRow row = sheet.CreateRow(0);
                            int columnIndex = 0;
                            foreach (var key in headers.Keys)
                            {
                                NPOI.SS.UserModel.ICell cell = row.CreateCell(columnIndex++);
                                cell.SetCellValue(headers[key]);
                                cell.CellStyle = titleStyle;
                                columnWidths.Add(key, headers[key].Length >= 4 ? 256 * (10 + headers[key].Length) : 12 * 256);
                            }
                        }
                        lastRowNum = 0;
                    }
                    int rowIndex = lastRowNum + 1;
                    int pRowIndex = 0;
                    int pRowTotal = objList == null ? 0 : objList.Count;
                    foreach (object obj2 in objList)
                    {
                        pRowIndex++;
                        if (showInfoDelagete != null)
                        {
                            showInfoDelagete($"请稍候，共 {pRowTotal} 条记录，正在处理第 {pRowIndex} 条");
                        }
                        int columnIndex = 0;
                        IRow row = sheet.CreateRow(rowIndex++);
                        foreach (var key in headers.Keys)
                        {
                            ICellStyle cellStyle = obj2 is IProduct && ((IProduct)obj2).GetForeColor(key) == System.Drawing.Color.Red ? redNormalStyle : normalStyle;
                            var value = string.Empty;
                            var cellFormula = "";
                            if (key.ToLower().Equals("id") && needRebuildId)
                            {
                                cellFormula = "ROW()-1";
                            }
                            else
                            {
                                try
                                {
                                    var p = pList.Find(v => v.Name.Equals(key));
                                    if (p != null)
                                    {
                                        var pValue = p.GetValue(obj2);
                                        if (p.PropertyType.IsEnum && IsTranEnumRealValue)
                                        {
                                            pValue = Enum.Format(p.PropertyType, pValue, "D");
                                        }
                                        value = pValue == null ? string.Empty : pValue.ToString();
                                    }
                                }
                                catch (Exception innerEx)
                                {
                                    LogHelper.Error(innerEx);
                                    value = string.Empty;
                                }
                            }
                            NPOI.SS.UserModel.ICell cell = row.CreateCell(columnIndex++);
                            if (!string.IsNullOrWhiteSpace(cellFormula))
                            {
                                cell.SetCellFormula(cellFormula);
                            }
                            else
                            {
                                cell.SetCellValue(value);
                            }
                            cell.CellStyle = cellStyle;
                            if (!string.IsNullOrWhiteSpace(value) && columnWidths != null && columnWidths.Count > 0)
                            {
                                int valueLen = 256 * (value.Length + 10);
                                columnWidths[key] = valueLen > columnWidths[key] ? valueLen : columnWidths[key];
                            }
                        }
                    }
                    if (overwrite || isNewFile)
                    {
                        for (var i = 0; i < columnWidths.Keys.Count; i++)
                        {
                            var tempKey = columnWidths.Keys.ElementAt(i);
                            var tempLen = columnWidths[tempKey];
                            sheet.SetColumnWidth(i, tempLen > 65280 ? 65280 : tempLen);
                        }
                    }
                    if (showInfoDelagete != null)
                    {
                        showInfoDelagete($"请稍候，开始保存到Excel文件中...");
                    }
                    sheet.ForceFormulaRecalculation = true;
                    using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                    {
                        workbook.Write(stream);
                    }
                    if (showInfoDelagete != null)
                    {
                        showInfoDelagete($"数据已保存到Excel文件中...");
                    }
                    workbook.Close();
                    workbook = null;
                    fs.Close();
                    fs = null;
                    result = true;
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
                finally
                {
                    if (workbook != null)
                    {
                        try
                        {
                            workbook.Close();
                        }
                        catch (Exception ex1)
                        {
                            LogHelper.Error(ex1);
                        }
                    }
                    if (fs != null)
                    {
                        try
                        {
                            fs.Close();
                        }
                        catch (Exception ex2)
                        {
                            LogHelper.Error(ex2);
                        }
                    }
                }
            }
            return result;
        }
        /// <summary>
        /// 根据字典数据生成Excel
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="dic"></param>
        /// <param name="overwrite"></param>
        public static bool WriteExcel(string filePath, Dictionary<string, object> dic, bool overwrite = false)
        {
            var sheetName = "数据";
            bool result = false;
            if (dic != null && dic.Keys.Count > 0)
            {
                FileStream fs = null;
                IWorkbook workbook = null;
                try
                {
                    List<string> headers = new List<string>() {
                        "参数名称","参数值"
                    };
                    bool isNewFile = CheckFile(filePath);
                    if (isNewFile)
                    {
                        NewExcelFile(filePath, headers, sheetName);
                    }
                    fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    workbook = new XSSFWorkbook(fs);
                    //获取表的位置
                    int sIndex = workbook.GetSheetIndex(sheetName);
                    ISheet sheet;
                    //-1则为空
                    if (sIndex == -1)
                    {
                        //创建新表
                        sheet = workbook.CreateSheet(sheetName);
                        //更新表位置索引
                        sIndex = workbook.GetSheetIndex(sheetName);
                    }
                    else
                    {
                        //按位置获取表
                        sheet = workbook.GetSheetAt(sIndex);
                    }
                    int lastRowNum = sheet.LastRowNum;
                    ICellStyle titleStyle = GetBoldStyle(workbook);
                    ICellStyle normalStyle = GetNormalStyle(workbook);
                    ICellStyle redNormalStyle = GetRedNormalStyle(workbook);
                    ICellStyle intStyle = GetIntStyle(workbook);
                    var columnWidths = new Dictionary<string, int>();
                    if (overwrite || isNewFile)
                    {
                        workbook.RemoveSheetAt(sIndex);
                        sheet = workbook.CreateSheet(sheetName);
                        if (headers != null && headers.Count > 0)
                        {
                            IRow row = sheet.CreateRow(0);
                            int columnIndex = 0;
                            foreach (var key in headers)
                            {
                                NPOI.SS.UserModel.ICell cell = row.CreateCell(columnIndex++);
                                cell.SetCellValue(key);
                                cell.CellStyle = titleStyle;
                            }
                        }
                        lastRowNum = 0;
                    }
                    int rowIndex = lastRowNum + 1;

                    foreach (string objKey in dic.Keys)
                    {
                        IRow row = sheet.CreateRow(rowIndex++);
                        ICellStyle cellStyle = normalStyle;
                        var value = dic[objKey].ToString();
                        NPOI.SS.UserModel.ICell cell0 = row.CreateCell(0);
                        NPOI.SS.UserModel.ICell cell1 = row.CreateCell(1);
                        cell0.CellStyle = cellStyle;
                        cell0.SetCellValue(objKey);
                        cell1.CellStyle = cellStyle;
                        cell1.SetCellValue(value);
                    }

                    sheet.SetColumnWidth(0, 25 * 256);
                    sheet.SetColumnWidth(1, 20 * 256);

                    using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                    {
                        workbook.Write(stream);
                    }
                    workbook.Close();
                    workbook = null;
                    fs.Close();
                    fs = null;
                    result = true;
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
                finally
                {
                    if (workbook != null)
                    {
                        try
                        {
                            workbook.Close();
                        }
                        catch (Exception ex1)
                        {
                            LogHelper.Error(ex1);
                        }
                    }
                    if (fs != null)
                    {
                        try
                        {
                            fs.Close();
                        }
                        catch (Exception ex2)
                        {
                            LogHelper.Error(ex2);
                        }
                    }
                }
            }
            return result;
        }


        private static string GetExcelCellStringValue(NPOI.SS.UserModel.ICell cell)
        {
            string result = "";
            if (cell != null)
            {
                result = cell.CellType == CellType.Numeric ? cell.NumericCellValue.ToString() :
                    (cell.CellType == CellType.Boolean ? cell.BooleanCellValue.ToString() : cell.StringCellValue);
            }
            return result;
        }
        /// <summary>
        /// 获取出站（一对多）配置
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="showInfoDelagete"></param>
        /// <returns></returns>
        public static List<MultiPLCTagParameter> ReadMultiStationTags(string filePath, ShowInfoDelagete showInfoDelagete = null)
        {
            List<MultiPLCTagParameter> list = new List<MultiPLCTagParameter>();
            if (File.Exists(filePath) && filePath.ToLower().EndsWith(".xlsx"))
            {
                FileStream fs = null;
                IWorkbook workbook = null;
                try
                {
                    fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    workbook = new XSSFWorkbook(fs);
                    ISheet sheet = workbook.GetSheetAt(0);
                    MultiPLCTagParameter tempTag = null;
                    if (sheet != null)
                    {
                        for (var i = 0; i <= sheet.LastRowNum; i++)
                        {
                            var row = sheet.GetRow(i);
                            if (row == null)
                            {
                                continue;
                            }
                            else
                            {
                                var firstCell = row.GetCell(0);
                                var secondCell = row.GetCell(1);
                                if (firstCell != null && secondCell != null)
                                {
                                    var firstCellValue = GetExcelCellStringValue(firstCell);
                                    var secondCellValue = GetExcelCellStringValue(secondCell);
                                    if (!string.IsNullOrWhiteSpace(firstCellValue) && !string.IsNullOrWhiteSpace(secondCellValue)
                                        && firstCellValue.Equals("备注") && secondCellValue.Equals("出站类型"))
                                    {
                                        if (tempTag != null)
                                        {
                                            list.Add(tempTag);
                                            tempTag = null;
                                        }
                                        //备注	出站类型	出站触发地址	出站结果地址	出站完成地址
                                        i++;
                                        row = sheet.GetRow(i);
                                        var remarkCell = row.GetCell(0);
                                        var outTypeCell = row.GetCell(1);
                                        var triggerCell = row.GetCell(2);
                                        var resultCell = row.GetCell(3);
                                        var doneCell = row.GetCell(4);

                                        if (remarkCell != null && !string.IsNullOrWhiteSpace(GetExcelCellStringValue(remarkCell))
                                            && outTypeCell != null && !string.IsNullOrWhiteSpace(GetExcelCellStringValue(outTypeCell))
                                            && triggerCell != null && !string.IsNullOrWhiteSpace(GetExcelCellStringValue(triggerCell)))
                                        {
                                            var remark = GetExcelCellStringValue(remarkCell);
                                            var outType = 0;
                                            int.TryParse(GetExcelCellStringValue(outTypeCell), out outType);
                                            var trigger = GetExcelCellStringValue(triggerCell);
                                            var result = resultCell == null || string.IsNullOrWhiteSpace(resultCell.StringCellValue) ? "" : resultCell.StringCellValue;
                                            var done = doneCell == null || string.IsNullOrWhiteSpace(doneCell.StringCellValue) ? "" : doneCell.StringCellValue;
                                            tempTag = new MultiPLCTagParameter()
                                            {
                                                Remark = remark,
                                                DoneAddress = done,
                                                OutType = CommonHelper.GetEnumByRealValue(outType, EOutType.FINAL),
                                                ResultAddress = result,
                                                TriggerAddress = trigger
                                            };
                                        }
                                    }
                                    else if (!string.IsNullOrWhiteSpace(firstCellValue) && !string.IsNullOrWhiteSpace(secondCellValue)
                                        && firstCellValue.Equals("PLC地址") && secondCellValue.Equals("数据类型")
                                        && tempTag != null)
                                    {
                                        List<PLCTagSetting> tagList = new List<PLCTagSetting>();
                                        int emptyRows = 0;
                                        //PLC地址	数据类型	实体属性	数据长度
                                        i++;
                                        for (; i <= sheet.LastRowNum; i++)
                                        {
                                            row = sheet.GetRow(i);
                                            if (row == null)
                                            {
                                                break;
                                            }
                                            var addressCell = row.GetCell(0);
                                            var dataTypeTypeCell = row.GetCell(1);
                                            var ormNameCell = row.GetCell(2);
                                            var dataLengthCell = row.GetCell(3);
                                            if (!string.IsNullOrWhiteSpace(GetExcelCellStringValue(addressCell))
                                                && !string.IsNullOrWhiteSpace(GetExcelCellStringValue(dataTypeTypeCell))
                                                && GetExcelCellStringValue(addressCell).Equals("备注")
                                                && GetExcelCellStringValue(dataTypeTypeCell).Equals("出站类型"))
                                            {
                                                i -= 1;
                                                break;
                                            }
                                            else if (!string.IsNullOrWhiteSpace(GetExcelCellStringValue(addressCell))
                                                && !string.IsNullOrWhiteSpace(GetExcelCellStringValue(dataTypeTypeCell))
                                                && GetExcelCellStringValue(addressCell).Equals("PLC地址")
                                                && GetExcelCellStringValue(dataTypeTypeCell).Equals("数据类型"))
                                            {
                                                if (tagList.Count > 0)
                                                {
                                                    tempTag.Parameters.Add(tagList);
                                                    tagList = new List<PLCTagSetting>();
                                                }
                                                continue;
                                            }
                                            if (addressCell != null && !string.IsNullOrWhiteSpace(GetExcelCellStringValue(addressCell))
                                                && dataTypeTypeCell != null && !string.IsNullOrWhiteSpace(GetExcelCellStringValue(dataTypeTypeCell))
                                                && ormNameCell != null && !string.IsNullOrWhiteSpace(GetExcelCellStringValue(ormNameCell)))
                                            {
                                                var address = GetExcelCellStringValue(addressCell);
                                                var dataType = GetExcelCellStringValue(dataTypeTypeCell);
                                                var ormName = GetExcelCellStringValue(ormNameCell);
                                                var length = 0;
                                                int.TryParse(GetExcelCellStringValue(dataLengthCell), out length);

                                                tagList.Add(new PLCTagSetting()
                                                {
                                                    len = length,
                                                    ORMName = ormName,
                                                    Tag = address,
                                                    TypeName = dataType
                                                });
                                            }
                                            else
                                            {
                                                emptyRows++;
                                                if (emptyRows >= 2)
                                                {
                                                    break;
                                                }
                                            }
                                        }
                                        if (tagList.Count > 0)
                                        {
                                            tempTag.Parameters.Add(tagList);
                                            tagList = new List<PLCTagSetting>();
                                        }
                                    }
                                }
                            }
                        }
                    }
                    if (tempTag != null)
                    {
                        list.Add(tempTag);
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
                if (workbook != null)
                {
                    try
                    {
                        workbook.Close();
                    }
                    catch (Exception ex1)
                    {
                        LogHelper.Error(ex1);
                    }
                }
                if (fs != null)
                {
                    try
                    {
                        fs.Close();
                    }
                    catch (Exception ex2)
                    {
                        LogHelper.Error(ex2);
                    }
                }
            }
            return list;
        }
        /// <summary>
        /// 把出站配置生成Excel（一对多）
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="objList"></param>
        /// <param name="sheetName"></param>
        /// <param name="showInfoDelagete"></param>
        /// <returns></returns>
        public static bool OutputMultiStationTagExcel(string filePath, List<MultiPLCTagParameter> objList,
            string sheetName = "数据",
            ShowInfoDelagete showInfoDelagete = null)
        {
            bool result = false;
            if (objList != null && objList.Count > 0)
            {
                FileStream fs = null;
                IWorkbook workbook = null;
                try
                {
                    CheckFile(filePath);
                    NewExcelFile(filePath, null, sheetName);
                    fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    workbook = new XSSFWorkbook(fs);
                    ISheet sheet = workbook.GetSheetAt(0);
                    ICellStyle titleStyle = GetBoldStyle(workbook);
                    ICellStyle normalStyle = GetNormalStyle(workbook);
                    ICellStyle redNormalStyle = GetRedNormalStyle(workbook);
                    ICellStyle intStyle = GetIntStyle(workbook);
                    int rowIndex = 0;
                    foreach (var tag in objList)
                    {
                        var titleRow = sheet.CreateRow(rowIndex);
                        var remarkCell = titleRow.CreateCell(0);
                        remarkCell.CellStyle = titleStyle;
                        remarkCell.SetCellValue("备注");
                        var outTypeCell = titleRow.CreateCell(1);
                        outTypeCell.CellStyle = titleStyle;
                        outTypeCell.SetCellValue("出站类型");
                        var triggerAddressCell = titleRow.CreateCell(2);
                        triggerAddressCell.CellStyle = titleStyle;
                        triggerAddressCell.SetCellValue("出站触发地址");
                        var resultAddressCell = titleRow.CreateCell(3);
                        resultAddressCell.CellStyle = titleStyle;
                        resultAddressCell.SetCellValue("出站结果地址");
                        var doneAddressCell = titleRow.CreateCell(4);
                        doneAddressCell.CellStyle = titleStyle;
                        doneAddressCell.SetCellValue("出站完成地址");
                        rowIndex += 1;
                        titleRow = sheet.CreateRow(rowIndex);
                        remarkCell = titleRow.CreateCell(0);
                        remarkCell.CellStyle = normalStyle;
                        remarkCell.SetCellValue($"{tag.Remark}");
                        outTypeCell = titleRow.CreateCell(1);
                        outTypeCell.CellStyle = intStyle;
                        outTypeCell.SetCellValue((int)tag.OutType);
                        triggerAddressCell = titleRow.CreateCell(2);
                        triggerAddressCell.CellStyle = normalStyle;
                        triggerAddressCell.SetCellValue($"{tag.TriggerAddress}");
                        resultAddressCell = titleRow.CreateCell(3);
                        resultAddressCell.CellStyle = normalStyle;
                        resultAddressCell.SetCellValue($"{tag.ResultAddress}");
                        doneAddressCell = titleRow.CreateCell(4);
                        doneAddressCell.CellStyle = normalStyle;
                        doneAddressCell.SetCellValue($"{tag.DoneAddress}");
                        rowIndex += 2;
                        foreach (var d in tag.Parameters)
                        {
                            titleRow = sheet.CreateRow(rowIndex);
                            remarkCell = titleRow.CreateCell(0);
                            remarkCell.CellStyle = titleStyle;
                            remarkCell.SetCellValue("PLC地址");
                            outTypeCell = titleRow.CreateCell(1);
                            outTypeCell.CellStyle = titleStyle;
                            outTypeCell.SetCellValue("数据类型");
                            triggerAddressCell = titleRow.CreateCell(2);
                            triggerAddressCell.CellStyle = titleStyle;
                            triggerAddressCell.SetCellValue("实体属性");
                            resultAddressCell = titleRow.CreateCell(3);
                            resultAddressCell.CellStyle = titleStyle;
                            resultAddressCell.SetCellValue("数据长度");
                            rowIndex += 1;
                            foreach (var vd in d)
                            {
                                titleRow = sheet.CreateRow(rowIndex);
                                remarkCell = titleRow.CreateCell(0);
                                remarkCell.CellStyle = normalStyle;
                                remarkCell.SetCellValue($"{vd.Tag}");
                                outTypeCell = titleRow.CreateCell(1);
                                outTypeCell.CellStyle = normalStyle;
                                outTypeCell.SetCellValue($"{vd.TypeName.ToUpper()}");
                                triggerAddressCell = titleRow.CreateCell(2);
                                triggerAddressCell.CellStyle = normalStyle;
                                triggerAddressCell.SetCellValue($"{vd.ORMName}");
                                resultAddressCell = titleRow.CreateCell(3);
                                resultAddressCell.CellStyle = intStyle;
                                resultAddressCell.SetCellValue(vd.len);
                                rowIndex += 1;
                            }
                            rowIndex += 1;
                        }
                    }
                    for (var i = 0; i < 5; i++)
                    {
                        sheet.SetColumnWidth(i, 20 * 256);
                    }
                    if (showInfoDelagete != null)
                    {
                        showInfoDelagete($"请稍候，开始保存到Excel文件中...");
                    }
                    using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                    {
                        workbook.Write(stream);
                    }
                    if (showInfoDelagete != null)
                    {
                        showInfoDelagete($"数据已保存到Excel文件中...");
                    }
                    workbook.Close();
                    workbook = null;
                    fs.Close();
                    fs = null;
                    result = true;
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
                finally
                {
                    if (workbook != null)
                    {
                        try
                        {
                            workbook.Close();
                        }
                        catch (Exception ex1)
                        {
                            LogHelper.Error(ex1);
                        }
                    }
                    if (fs != null)
                    {
                        try
                        {
                            fs.Close();
                        }
                        catch (Exception ex2)
                        {
                            LogHelper.Error(ex2);
                        }
                    }
                }
            }
            return result;
        }
        static object obj11 = new object();
        /// <summary>
        /// ListView内容生成Excel
        /// </summary>
        /// <param name="listView"></param>
        /// <param name="filePath"></param>
        public static void ListViewToExcel(ListView listView, string filePath)
        {
            lock (obj11)
            {
                if (listView != null)
                {
                    IWorkbook workbook = null;
                    try
                    {
                        bool isNewFile = CheckFile(filePath);
                        workbook = new XSSFWorkbook();
                        ISheet sheet = workbook.CreateSheet("数据");
                        ICellStyle titleStyle = GetBoldStyle(workbook);
                        ICellStyle normalStyle = GetNormalStyle(workbook);
                        ICellStyle redNormalStyle = GetRedNormalStyle(workbook);
                        IRow row = null;
                        NPOI.SS.UserModel.ICell cell = null;
                        int rowIndex = 0;
                        int columnIndex = 0;
                        row = sheet.CreateRow(rowIndex++);
                        foreach (ColumnHeader c in listView.Columns)
                        {
                            cell = row.CreateCell(columnIndex++);
                            cell.CellStyle = titleStyle;
                            cell.SetCellValue(c.Text);
                            sheet.AutoSizeColumn(columnIndex - 1);
                        }
                        foreach (ListViewItem rowItem in listView.Items)
                        {
                            columnIndex = 0;
                            row = sheet.CreateRow(rowIndex++);
                            if (rowItem.SubItems != null)
                            {
                                for (var k = 0; k < rowItem.SubItems.Count; k++)
                                {
                                    cell = row.CreateCell(columnIndex++);
                                    cell.CellStyle = rowItem.ForeColor == Color.Red ? redNormalStyle : normalStyle;
                                    cell.SetCellValue(rowItem.SubItems[k].Text);
                                }
                            }
                        }
                        using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                        {
                            workbook.Write(stream);
                            workbook.Close();
                            workbook = null;
                        }
                        HWMessageBox.Show(null, "导出成功");
                    }
                    catch (Exception ex)
                    {
                        HWMessageBox.Show(null, ex.Message);
                    }
                    finally
                    {
                        if (workbook != null)
                        {
                            try
                            {
                                workbook.Close();
                                workbook = null;
                            }
                            catch (Exception ex1)
                            {
                                LogHelper.Error(ex1);
                            }

                        }
                    }
                }
            }

        }
        /// <summary>
        /// 打开Word文件
        /// </summary>
        /// <param name="url"></param>
        /// <param name="args"></param>
        public static void OpenWordFile(string url, string args = null)
        {
            try
            {
                System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(url)
                {
                    UseShellExecute = true,
                    Arguments = args,
                    Verb = "open"
                });
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }
        /// <summary>
        /// 打开Excel文档
        /// </summary>
        /// <param name="url"></param>
        /// <param name="args"></param>
        public static void OpenExcelFile(string url, string args = null)
        {
            try
            {
                System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(url)
                {
                    UseShellExecute = true,
                    Arguments = args,
                    Verb = "open"
                });
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }
        /// <summary>
        /// 字节数组转为结构体
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object BytesToStruct(byte[] bytes, Type type)
        {
            int size = Marshal.SizeOf(type);
            if (size > bytes.Length)
            {
                return null;
            }
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            Marshal.Copy(bytes, 0, structPtr, size);
            object obj = Marshal.PtrToStructure(structPtr, type);
            Marshal.FreeHGlobal(structPtr);
            return obj;
        }
        /// <summary>
        /// 把文件内容转换为指定对象列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="path"></param>
        /// <returns></returns>

        public static List<T> GetJsonListFromFile<T>(string path)
        {
            List<T> list = new List<T>();
            try
            {
                CheckFile(path);
                string content = File.ReadAllText(path, ENCODING);
                if (string.IsNullOrWhiteSpace(content))
                {
                    list = new List<T>();
                }
                else
                {
                    list = JsonConvert.DeserializeObject<List<T>>(content);
                    if (list == null)
                    {
                        list = new List<T>();
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
            return list;
        }
        /// <summary>
        /// 获取对象属性的名称跟描述
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static List<CNameDesc> GetNameDescList(object obj)
        {
            List<CNameDesc> list = new List<CNameDesc>();
            var fields = obj.GetType().GetProperties();
            foreach (var field in fields)
            {
                var name = field.Name;
                var desc = name;
                var descAttr = field.GetCustomAttribute(typeof(DescriptionAttribute));
                if (null != desc)
                {
                    desc = ((DescriptionAttribute)descAttr).Description;
                }
                list.Add(new CNameDesc { Description = desc, Name = name });
            }
            return list;
        }
        /// <summary>
        /// 把对象内容保存到JSON文件中
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="path"></param>
        public static void SaveToJsonFile(object obj, string path)
        {
            CheckFile(path);
            string content = obj != null ? JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.Indented) : string.Empty;
            bool isSuccess = false;
            for (var i = 0; i < 3; i++)
            {
                try
                {
                    File.WriteAllText(path, content, ENCODING);
                    isSuccess = true;
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
                if (isSuccess)
                {
                    break;
                }
            }
        }
        /// <summary>
        /// 检查文件所在的文件夹是否存在，若不存在可以自动创建
        /// </summary>
        /// <param name="fileName"></param>
        public static void CheckDirectory(string fileName)
        {
            try
            {
                if (!string.IsNullOrWhiteSpace(fileName) && !File.Exists(fileName))
                {
                    FileInfo file = new FileInfo(fileName);
                    DirectoryInfo dir = file.Directory;
                    if (!dir.Exists)
                    {
                        Directory.CreateDirectory(dir.FullName);
                        dir.Refresh();
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }

        /// <summary>
        /// 检查文件是否存在，若不存在则新建并返回TRUE
        /// </summary>
        /// <param name="fileName">完整完整路径</param>
        /// <returns>TRUE表示存在，FALSE表示不存在</returns>
        /// <example>
        /// <code>CommonHelper.CheckFile(@"C:\abc.txt");</code>
        /// </example>
        public static bool CheckFile(string fileName)
        {
            bool isnewfile = false;
            //判断文件是否存在
            if (!File.Exists(fileName))
            {
                //判断路径是否存在
                if (!Directory.Exists(Path.GetFullPath(fileName)))
                {
                    //路径不存在
                    //创建路径
                    Directory.CreateDirectory(Path.GetDirectoryName(fileName));
                }
                var myFile = File.Create(fileName);
                myFile.Close();
                isnewfile = true;
            }
            return isnewfile;
        }
        /// <summary>
        /// 拆分指定字符串内容
        /// A:120;B:150
        /// </summary>
        /// <param name="resultAddress"></param>
        /// <returns></returns>
        public static IEnumerable<KeyValuePair<string, string>> GetResultAddressDic(string resultAddress)
        {
            Dictionary<string, string> resultDic = new Dictionary<string, string>();
            if (!string.IsNullOrWhiteSpace(resultAddress))
            {
                string[] parameters = resultAddress.Split(SplitParameterArray, StringSplitOptions.RemoveEmptyEntries);
                foreach (var pv in parameters)
                {
                    string[] pvs = pv.Split(SplitValueArray, StringSplitOptions.RemoveEmptyEntries);
                    if (pvs != null && pvs.Length == 2)
                    {
                        yield return new KeyValuePair<string, string>(pvs[0], pvs[1]);
                    }
                }
            }
        }
        /// <summary>
        /// 把对象内容写入 csv 文件
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="obj"></param>

        public static void WriteCSV(string filePath, object obj)
        {
            StreamWriter writer = null;
            StreamReader reader = null;
            try
            {
                bool isNewFile = CheckFile(filePath);
                List<PropertyInfo> pList = new List<PropertyInfo>();
                var result = GetCSVHeader(obj);
                Dictionary<string, string> headers = result.dic;
                pList = result.pList;
                List<string> contents = new List<string>();
                foreach (var key in headers.Keys)
                {
                    var value = string.Empty;
                    try
                    {
                        var p = pList.Find(v => v.Name.Equals(key));
                        if (p != null)
                        {
                            var pValue = p.GetValue(obj);
                            value = pValue == null ? string.Empty : pValue.ToString();
                        }
                    }
                    catch (Exception innerEx)
                    {
                        LogHelper.Error(innerEx);
                    }
                    contents.Add(value);
                }
                writer = new StreamWriter(filePath, true, ENCODING);
                if (isNewFile)
                {
                    writer.WriteLine(string.Join(",", headers.Values));
                }
                writer.WriteLine(string.Join(",", contents));
                writer.Close();
                writer = null;
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
            finally
            {
                if (reader != null)
                {
                    try
                    {
                        reader.Close();
                    }
                    catch (Exception re)
                    {
                        LogHelper.Error(re);
                    }
                }
                if (writer != null)
                {
                    try
                    {
                        writer.Close();
                    }
                    catch (Exception we)
                    {
                        LogHelper.Error(we);
                    }
                }
            }
        }
        /// <summary>
        /// 获取枚举描述
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string GetEnumDescription(Enum value)
        {
            string val = value.ToString();
            FieldInfo field = value.GetType().GetField(val);
            object[] objs = field.GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (null == objs || objs.Length == 0)
            {
                return val;
            }
            DescriptionAttribute da = (DescriptionAttribute)objs[0];
            return da.Description;
        }
        /// <summary>
        /// 获取枚举描述
        /// </summary>
        /// <returns></returns>
        public static Dictionary<string, int> GetEnumDescription<T>()
        {
            Dictionary<string, int> result = new Dictionary<string, int>();
            FieldInfo[] fields = typeof(T).GetFields();
            foreach (var field in fields)
            {
                object[] objs = field.GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (null != objs && objs.Length > 0)
                {
                    result.Add(((DescriptionAttribute)objs[0]).Description, (int)Enum.Parse(typeof(T), field.Name));
                }
            }
            return result;
        }
        /// <summary>
        /// 把文件内容转换为指定对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="path"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static T GetJsonFromFile<T>(string path, T defaultValue)
        {
            T result = defaultValue;
            try
            {
                CheckFile(path);
                string content = File.ReadAllText(path, ENCODING);
                if (!string.IsNullOrWhiteSpace(content))
                {
                    result = JsonConvert.DeserializeObject<T>(content);
                    if (result == null)
                    {
                        result = defaultValue;
                    }
                }
            }
            catch (Exception ex)
            {
                result = defaultValue;
                LogHelper.Error(ex);
            }
            return result;
        }
        /// <summary>
        /// 结构体转为字节数组
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static byte[] StructToBytes(object obj)
        {
            int size = Marshal.SizeOf(obj);
            byte[] bytes = new byte[size];
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(obj, structPtr, false);
            Marshal.Copy(structPtr, bytes, 0, size);
            Marshal.FreeHGlobal(structPtr);
            return bytes;
        }
        /// <summary>
        /// 删除回车换行
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string RemoveEnterString(string value)
        {
            string result = value;
            if (!string.IsNullOrWhiteSpace(result))
            {
                if (result.EndsWith("\r\n"))
                {
                    result = result.Substring(0, result.Length - 2);
                }
                else if (result.EndsWith("\n"))
                {
                    result = result.Substring(0, result.Length - 1);
                }
                else if (result.EndsWith("\r"))
                {
                    result = result.Substring(0, result.Length - 1);
                }
                else if (result.EndsWith("\\r"))
                {
                    result = result.Substring(0, result.Length - 2);
                }
                result = result.TrimEnd(EMPTY_END_CHAR_ARRAY);
            }
            return result;
        }
        /// <summary>
        /// 根据值获取枚举值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static T GetEnumByRealValue<T>(object value, T defaultValue)
          where T : Enum
        {
            T result = defaultValue;
            try
            {
                string name = Enum.GetName(typeof(T), value);
                if (!string.IsNullOrWhiteSpace(name))
                {
                    result = GetEnumByName(name, defaultValue);
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex, "", $"value={value}，defaultValue={defaultValue}");
            }
            return result;
        }
        /// <summary>
        /// 根据名称获取枚举值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static T GetEnumByName<T>(string name, T defaultValue)
        {
            T result = defaultValue;
            if (!string.IsNullOrWhiteSpace(name))
            {
                try
                {
                    result = (T)Enum.Parse(typeof(T), name, true);
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex, "", $"name={name}，defaultValue={defaultValue}");
                }
            }
            return result;
        }
        /// <summary>
        /// 根据枚举描述获取枚举值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="description"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static T GetEnumByDescription<T>(string description, T defaultValue)
          where T : Enum
        {
            T result = defaultValue;
            if (!string.IsNullOrWhiteSpace(description))
            {
                try
                {
                    var dic = GetEnumDescription<T>();
                    if (dic != null && dic.ContainsKey(description))
                    {
                        result = GetEnumByRealValue(dic[description], defaultValue);
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex, "", $"description={description}，defaultValue={defaultValue}");
                }
            }
            return result;
        }

        /// <summary>
        /// 获取数字部分值
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string GetNumberFromString(string s)
        {
            string number = string.Empty;
            if (!string.IsNullOrWhiteSpace(s))
            {
                Regex regex = new Regex("[0-9.]+");
                var match = regex.Match(s);

                if (match.Success)
                {
                    number = match.Value.TrimStart(ZERO_START_ARRAY);
                    number = number.StartsWith(".") ? $"0{number}" : number;
                }
            }
            return number;
        }
        /// <summary>
        /// 把字典内容转换为字符串
        /// </summary>
        /// <param name="dic"></param>
        /// <param name="lineSplit"></param>
        /// <returns></returns>
        public static string DictionaryToString(Dictionary<string, string> dic, string lineSplit = "\r\n")
        {
            StringBuilder sb = new StringBuilder();
            foreach (string key in dic.Keys)
            {
                sb.Append($"{key}: {dic[key]}{lineSplit}");
            }
            return sb.ToString();
        }
        /// <summary>
        /// 获取对象描述信息
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string GetStructString(object obj)
        {
            return DictionaryToString(GetStructDic(obj), "  ");
        }
        /// <summary>
        /// 获取对象描述信息
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string GetObjectString(object obj)
        {
            var fields = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            StringBuilder sb = new StringBuilder();
            foreach (var field in fields)
            {
                var val = field.GetValue(obj);
                var typeName = field.PropertyType.Name.ToLower();
                var text = val == null ? "" : val.ToString();
                var title = field.Name;
                var desc = field.GetCustomAttribute(typeof(DescriptionAttribute));
                if (null != desc)
                {
                    title = ((DescriptionAttribute)desc).Description;
                }
                switch (typeName)
                {
                    case "byte[]": text = string.Join(" ", ((byte[])val).Select(x => x.ToString("X2"))); break;
                    case "byte": text = ((byte)val).ToString("X2"); break;
                }
                sb.Append($"{title}: {text}\t");
            }
            return sb.ToString();
        }

        /// <summary>
        /// 把结构体信息转换为字典形式
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static Dictionary<string, string> GetStructDic(object obj)
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            var fields = obj.GetType().GetFields();
            foreach (var field in fields)
            {
                var val = field.GetValue(obj);
                var typeName = field.FieldType.Name.ToLower();
                var text = string.Empty;
                var title = field.Name;
                var desc = field.GetCustomAttribute(typeof(DescriptionAttribute));
                var div = field.GetCustomAttribute(typeof(DivisionAttribute));
                if (null != desc)
                {
                    title = ((DescriptionAttribute)desc).Description;
                }
                if (null != val)
                {
                    switch (typeName)
                    {
                        case "byte[]":
                            byte[] buffer = (byte[])val;
                            int len = buffer.Length;
                            long temp = 0;
                            if (len > 0)
                            {
                                switch (len)
                                {
                                    case 1: temp = CommonHelper.GetShort(new byte[] { 0x00, (byte)val }); break;
                                    case 2: temp = CommonHelper.GetShort(buffer); break;
                                    case 3: temp = CommonHelper.GetInt(new byte[] { 0x00 }.Concat(buffer).ToArray()); break;
                                    case 4: temp = CommonHelper.GetInt(buffer); break;
                                    case 5: temp = CommonHelper.GetLong(new byte[] { 0x00, 0x00, 0x00 }.Concat(buffer).ToArray()); break;
                                    case 6: temp = CommonHelper.GetLong(new byte[] { 0x00, 0x00 }.Concat(buffer).ToArray()); break;
                                    case 7: temp = CommonHelper.GetLong(new byte[] { 0x00 }.Concat(buffer).ToArray()); break;
                                    case 8: temp = CommonHelper.GetLong(buffer); break;
                                    default: text = string.Join(" ", ((byte[])val).Select(x => x.ToString("X2"))); break;
                                }
                                if (len <= 8)
                                {
                                    text = temp.ToString();
                                    if (null != div)
                                    {
                                        DivisionAttribute divObj = (DivisionAttribute)div;
                                        float tempFloat = (temp * 1.0f) / divObj.DivValue;

                                        text = tempFloat.ToString(divObj.FormatValue);
                                    }
                                }
                            }
                            break;
                        case "byte": text = CommonHelper.GetShort(new byte[] { 0x00, (byte)val }).ToString(); break;
                    }
                }
                dic.Add(title, text);
            }
            return dic;
        }

        /// <summary>
        /// 从字节数组中获取数值，按高低字节
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="isSourceLittleEndian"></param>
        /// <returns></returns>
        public static short GetShort(byte[] bytes, bool isSourceLittleEndian = false)
        {
            short result = -1;
            if (bytes != null && bytes.Length == 2)
            {
                if (isSourceLittleEndian && BitConverter.IsLittleEndian)
                {
                    result = BitConverter.ToInt16(bytes, 0);
                }
                else
                {
                    result = BitConverter.ToInt16(bytes.Reverse().ToArray(), 0);
                }
            }
            return result;
        }
        /// <summary>
        /// 把字节数组转换为整数
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="isSourceLittleEndian"></param>
        /// <returns></returns>
        public static int GetInt(byte[] bytes, bool isSourceLittleEndian = false)
        {
            int result = -1;
            if (bytes != null && bytes.Length == 4)
            {
                if (isSourceLittleEndian && BitConverter.IsLittleEndian)
                {
                    result = BitConverter.ToInt32(bytes, 0);
                }
                else
                {
                    result = BitConverter.ToInt32(bytes.Reverse().ToArray(), 0);
                }
            }
            return result;
        }
        /// <summary>
        /// 把字节数组转换为长整数
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="isSourceLittleEndian"></param>
        /// <returns></returns>
        public static long GetLong(byte[] bytes, bool isSourceLittleEndian = false)
        {
            long result = -1;
            if (bytes != null && bytes.Length == 8)
            {
                if (isSourceLittleEndian && BitConverter.IsLittleEndian)
                {
                    result = BitConverter.ToInt64(bytes, 0);
                }
                else
                {
                    result = BitConverter.ToInt64(bytes.Reverse().ToArray(), 0);
                }
            }
            return result;
        }

        /// <summary>
        /// Ping IP
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public static bool DoPing(string ip)
        {
            bool result = false;
            Ping ping = new Ping();
            if (!string.IsNullOrWhiteSpace(ip))
            {
                try
                {
                    var status = ping.Send(ip, BusinessConfig.Instance().PingTimeout).Status;
                    result = status == IPStatus.Success ? true : false;
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex, "", ip);
                }
            }
            return result;
        }
        /// <summary>
        /// 响应窗体行为
        /// </summary>
        /// <param name="Milliseconds"></param>
        public static void ApplicationEvents(int Milliseconds = 90)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            for (var i = 0; i < 100000; i++)
            {
                Application.DoEvents();
                if (stopwatch.ElapsedMilliseconds >= Milliseconds)
                {
                    break;
                }
            }
            stopwatch.Stop();
        }
        /// <summary>
        /// 把Excel内容转换为对象列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filePath"></param>
        /// <param name="showInfoDelagete"></param>
        /// <returns></returns>
        public static List<T> ReadExcel<T>(string filePath, ShowInfoDelagete showInfoDelagete = null)
            where T : new()
        {
            var headAndPty = GetCSVHeader(new T());
            var headers = headAndPty.dic;
            List<T> list = new List<T>();
            if (File.Exists(filePath) && filePath.ToLower().EndsWith(".xlsx") && headers != null && headers.Keys.Count > 0)
            {
                FileStream fs = null;
                IWorkbook workbook = null;
                try
                {
                    fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    workbook = new XSSFWorkbook(fs);
                    ISheet sheet = workbook.GetSheetAt(0);
                    if (sheet != null)
                    {
                        int headerRowIndex = -1;
                        bool validHeaders = false;
                        var lastRowIndex = sheet.LastRowNum;
                        int rowIndex = 0;
                        do
                        {
                            var row = sheet.GetRow(rowIndex);
                            if (row != null && row.Cells != null && row.Cells.Count > 0)
                            {
                                for (var i = 0; i < row.LastCellNum; i++)
                                {
                                    var cell = row.GetCell(i);
                                    if (cell != null && cell.CellType == CellType.String && !string.IsNullOrWhiteSpace(cell.StringCellValue) &&
                                      headers.Values.Contains(cell.StringCellValue))
                                    {
                                        headerRowIndex = rowIndex;
                                        validHeaders = true;
                                        break;
                                    }
                                }
                            }
                        }
                        while (rowIndex <= lastRowIndex && rowIndex == -1);
                        if (validHeaders && rowIndex <= lastRowIndex)
                        {
                            Dictionary<string, int> headerColumns = new Dictionary<string, int>();
                            var headerRow = sheet.GetRow(rowIndex);
                            bool isFullHeaders = true;
                            for (var i = 0; i < headerRow.LastCellNum; i++)
                            {
                                var headerCell = headerRow.GetCell(i);
                                if (headerCell != null && headerCell.CellType == CellType.String && !string.IsNullOrWhiteSpace(headerCell.StringCellValue)
                                    && headers.Values.Contains(headerCell.StringCellValue))
                                {
                                    var tempKey = headers.Where(v => v.Value.Equals(headerCell.StringCellValue)).FirstOrDefault().Key;

                                    headerColumns.Add(tempKey, i);
                                }
                                else
                                {
                                    isFullHeaders = false;
                                }
                            }
                            if (!isFullHeaders)
                            {
                                if (showInfoDelagete != null)
                                {
                                    showInfoDelagete($"存在不合适的标题");
                                }
                            }
                            else
                            {
                                if (headerColumns.Count > 0)
                                {
                                    rowIndex++;
                                    while (rowIndex <= sheet.LastRowNum)
                                    {
                                        var row = sheet.GetRow(rowIndex);
                                        if (row != null)
                                        {
                                            bool isValidRow = false;
                                            T obj = new T();
                                            for (var i = 0; i < row.LastCellNum; i++)
                                            {
                                                var cell = row.GetCell(i);
                                                if (cell != null && headerColumns.ContainsValue(i))
                                                {
                                                    var p = headAndPty.pList.Find(v => v.Name.Equals(headerColumns.Where(k => k.Value.Equals(i)).FirstOrDefault().Key));

                                                    if (p != null)
                                                    {
                                                        if ((p.PropertyType.Equals(typeof(int)) || p.PropertyType.Equals(typeof(Int32))) && cell.CellType == CellType.Numeric)
                                                        {
                                                            p.SetValue(obj, (int)cell.NumericCellValue);
                                                        }
                                                        else if ((p.PropertyType.Equals(typeof(float)) || p.PropertyType.Equals(typeof(decimal))) && cell.CellType == CellType.Numeric)
                                                        {
                                                            p.SetValue(obj, (float)cell.NumericCellValue);
                                                        }
                                                        else if (p.PropertyType.Equals(typeof(double)) && cell.CellType == CellType.Numeric)
                                                        {
                                                            p.SetValue(obj, cell.NumericCellValue);
                                                        }
                                                        else if (p.PropertyType.Equals(typeof(long)) && cell.CellType == CellType.Numeric)
                                                        {
                                                            p.SetValue(obj, (long)cell.NumericCellValue);
                                                        }
                                                        else if ((p.PropertyType.Equals(typeof(Int16)) || p.PropertyType.Equals(typeof(short))) && cell.CellType == CellType.Numeric)
                                                        {
                                                            p.SetValue(obj, (short)cell.NumericCellValue);
                                                        }
                                                        else if ((p.PropertyType.Equals(typeof(UInt16)) || p.PropertyType.Equals(typeof(ushort))) && cell.CellType == CellType.Numeric)
                                                        {
                                                            p.SetValue(obj, (ushort)cell.NumericCellValue);
                                                        }
                                                        else if (p.PropertyType.Equals(typeof(ulong)) && cell.CellType == CellType.Numeric)
                                                        {
                                                            p.SetValue(obj, (ulong)cell.NumericCellValue);
                                                        }
                                                        else if ((p.PropertyType.Equals(typeof(uint)) || p.PropertyType.Equals(typeof(UInt32))) && cell.CellType == CellType.Numeric)
                                                        {
                                                            p.SetValue(obj, (uint)cell.NumericCellValue);
                                                        }
                                                        else if ((p.PropertyType.Equals(typeof(string)) || p.PropertyType.Equals(typeof(String))) && cell.CellType == CellType.String)
                                                        {
                                                            p.SetValue(obj, string.IsNullOrWhiteSpace(cell.StringCellValue) ? string.Empty : cell.StringCellValue);
                                                        }
                                                        else if ((p.PropertyType.Equals(typeof(bool)) || p.PropertyType.Equals(typeof(Boolean))) && cell.CellType == CellType.String)
                                                        {
                                                            bool bValue = false;
                                                            if (!string.IsNullOrWhiteSpace(cell.StringCellValue) && bool.TryParse(cell.StringCellValue, out bValue))
                                                            {
                                                                p.SetValue(obj, bValue);
                                                            }
                                                        }
                                                        isValidRow = true;
                                                    }
                                                }
                                            }
                                            if (isValidRow)
                                            {
                                                list.Add(obj);
                                            }
                                        }
                                        rowIndex++;
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
                if (workbook != null)
                {
                    try
                    {
                        workbook.Close();
                    }
                    catch (Exception ex1)
                    {
                        LogHelper.Error(ex1);
                    }
                }
                if (fs != null)
                {
                    try
                    {
                        fs.Close();
                    }
                    catch (Exception ex2)
                    {
                        LogHelper.Error(ex2);
                    }
                }
            }
            return list;
        }
        /// <summary>
        /// 打开并读取Excel文件内容
        /// </summary>
        /// <returns></returns>
        public static IWorkbook OpenAndReadExcel()
        {
            Console.WriteLine("OpenAndReadExcel");
            OpenFileDialog dialog = new OpenFileDialog()
            {
                Multiselect = true,//该值确定是否可以选择多个文件
                Title = "请选择文件",
                Filter = "Excel.文件|*.xlsx|Excel文件|*..xls"
            };
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                string fileName = @dialog.FileName;
                IWorkbook workbook;//创建一个工作薄接口
                string fileExt = Path.GetExtension(fileName).ToLower();//获取文件的拓展名
                using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
                {
                    if (fileExt == ".xlsx")
                    {
                        workbook = new XSSFWorkbook(fs);
                    }
                    else
                    {
                        workbook = null;
                    }
                }
                return workbook;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 获取属性描述
        /// </summary>
        /// <param name="property"></param>
        /// <returns></returns>
        public static string GetDescription(PropertyInfo property)
        {
            object[] description = property.GetCustomAttributes(typeof(DescriptionAttribute), true);
            if (description == null) return string.Empty;
            string descriptionString = ((DescriptionAttribute)description[0]).Description;
            return descriptionString;
        }
        /// <summary>
        /// 根据属性描述，将属性值放入Model中，单条数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="descriptoinName"></param>
        /// <param name="model"></param>
        /// <param name="row"></param>
        /// <returns></returns>
        public static void GetDescriptoinToProperty<T>(List<string> descriptoinName, T model, IRow row)
        {
            try
            {
                PropertyInfo[] properties = typeof(T).GetProperties();
                for (int j = row.FirstCellNum; j < row.LastCellNum; j++)
                {
                    if (row.GetCell(j) != null)
                    {
                        PropertyInfo property = properties.First(p => descriptoinName[j].Equals(GetDescription(p)));
                        object value = row.GetCell(j).ToString();
                        if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable)))
                        {
                            property.SetValue(model, Convert.ChangeType(value,
                                Nullable.GetUnderlyingType(property.PropertyType)), null);
                        }
                        else if (property.PropertyType.IsEnum)
                        {
                            if (!string.IsNullOrWhiteSpace(value.ToString()))
                            {
                                property.SetValue(model, GetEnumByRealValue(value, EOutType.FINAL), null);
                            }
                        }
                        else if (property.PropertyType.Name.Equals("Int32"))
                        {
                            if (!string.IsNullOrWhiteSpace(value.ToString()))
                            {
                                property.SetValue(model, Convert.ChangeType(value,
                                    property.PropertyType), null);
                            }
                        }
                        else
                        {
                            property.SetValue(model, Convert.ChangeType(value,
                                property.PropertyType), null);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }
        /// <summary>
        /// excel转modelList，全部数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filePath"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public static List<T> GetExcelToModelList<T>(string filePath, string tableName)
            where T : new()
        {
            List<T> list = new List<T>();
            try
            {
                FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                IWorkbook workbook = new XSSFWorkbook(fs);
                //获取表的位置
                int sheetIndex = workbook.GetSheetIndex(tableName);
                //为-1则代表空
                if (sheetIndex == -1)
                {
                    return list;
                }
                //实例化sheet
                ISheet sheet = workbook.GetSheetAt(sheetIndex);
                //默认第一行起始位置为0
                int FirstRowNum = 0;
                //跳过空行以及数据为空的行，重新设置第一行位置
                for (int i = 0; i < sheet.LastRowNum; i++)
                {
                    IRow rowValue = sheet.GetRow(i);
                    if (rowValue != null)
                    {
                        int j;
                        for (j = 0; j < rowValue.LastCellNum; j++)
                        {
                            ICell colCell = rowValue.GetCell(j);
                            if (colCell != null && !string.IsNullOrWhiteSpace(colCell.ToString()))
                            {
                                break;
                            }
                        }
                        if (j != rowValue.LastCellNum)
                        {
                            FirstRowNum = i;
                            break;
                        }
                    }
                }
                //获取表头
                IRow header = sheet.GetRow(FirstRowNum);
                int startRow = FirstRowNum + 1;//数据从有数据的第二行开始读
                List<string> listFirstCellName = new List<string>();
                //遍历表有数据的第一行，即所有的列名
                for (int i = header.FirstCellNum; i < header.LastCellNum; i++)
                {
                    ICell cell = header.GetCell(i);
                    if (cell != null)
                    {
                        //获取列名的值
                        string cellValue = cell.ToString();
                        if (cellValue != null)
                        {
                            listFirstCellName.Add(cellValue);
                        }
                    }
                }
                //读取数据
                for (int i = startRow; i <= sheet.LastRowNum; i++)
                {
                    IRow row = sheet.GetRow(i);
                    if (row == null)
                    {
                        continue;
                    }
                    T modelValue = new T();
                    GetDescriptoinToProperty(listFirstCellName, modelValue, row);
                    list.Add(modelValue);
                }
                workbook?.Close();
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
            return list;
        }
        /// <summary>
        /// 判断对象属性是否为空，若在前num个出现空则返回true
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <param name="necessaryProperties"></param>
        /// <returns></returns>
        public static bool IsNotNullContent<T>(T item, params string[] necessaryProperties)
        {
            bool result = true;
            if (item != null && necessaryProperties != null)
            {
                PropertyInfo[] properties = typeof(T).GetProperties();
                int total = 0;
                foreach (PropertyInfo property in properties)
                {
                    if (necessaryProperties.Contains(property.Name))
                    {
                        var value = property.GetValue(item, null);
                        //下面这句还可以再细化一下
                        bool isNotNull = value != null && !property.PropertyType.IsArray && !property.PropertyType.IsGenericType && !string.IsNullOrWhiteSpace(value.ToString());
                        total = isNotNull ? (total + 1) : total;
                    }
                }
                result = total == necessaryProperties.Length;
            }
            return result;
        }
        /// <summary>
        /// 十六进制字符串变成Byte数组
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        public static byte[] HexStringToBytes(string hexString)
        {
            byte[] result = null;
            if (!string.IsNullOrWhiteSpace(hexString))
            {
                hexString = hexString.Replace(" ", "");
                int len = hexString.Length;
                if (len > 0 && len % 2 == 0)
                {
                    result = new byte[len / 2];
                    for (int i = 0; i < len / 2; i++)
                    {
                        result[i] = byte.Parse(hexString.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
                    }
                }
            }
            return result;
        }
        /// <summary>
        /// Byte数组转换成字符串
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string BytesToHexString(byte[] bytes)
        {
            string result = string.Empty;
            if (bytes != null && bytes.Length > 0)
            {
                StringBuilder sb = new StringBuilder();
                foreach (byte b in bytes)
                {
                    sb.Append(b.ToString("X2"));
                }
                result = sb.ToString();
            }
            return result;
        }
        /// <summary>
        /// 字符串转换值，若不成功则会有各自的默认值
        /// 数字型的为0
        /// 字符串型的为空字符
        /// 布尔类型的为false
        /// </summary>
        /// <param name="typeName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static object ConvertValue(string typeName, string value)
        {
            object result = null;
            if (!string.IsNullOrWhiteSpace(typeName))
            {
                short shortValue = 0;
                ushort ushortValue = 0;
                int intValue = 0;
                uint uintValue = 0;
                long longValue = 0;
                ulong ulongValue = 0;
                float floatValue = 0;
                decimal decimalValue = 0;
                double doubleValue = 0f;
                bool boolValue = false;
                switch (typeName.ToLower())
                {
                    case "string": result = value; break;
                    case "short": case "int16": short.TryParse(value, out shortValue); result = shortValue; break;
                    case "ushort": case "uint16": ushort.TryParse(value, out ushortValue); result = ushortValue; break;
                    case "int": case "int32": int.TryParse(value, out intValue); result = intValue; break;
                    case "uint": case "uint32": uint.TryParse(value, out uintValue); result = uintValue; break;
                    case "long": case "int64": long.TryParse(value, out longValue); result = longValue; break;
                    case "ulong": case "uint64": ulong.TryParse(value, out ulongValue); result = ulongValue; break;
                    case "float": float.TryParse(value, out floatValue); result = floatValue; break;
                    case "decimal": decimal.TryParse(value, out decimalValue); result = decimalValue; break;
                    case "double": double.TryParse(value, out doubleValue); result = doubleValue; break;
                    case "bool": bool.TryParse(value, out boolValue); result = boolValue; break;
                }
            }
            return result;
        }

        private static readonly char[] ZERO_END_TRIM = new char[] { '0' };
        /// <summary>
        /// 获取科学计数法字符串
        /// </summary>
        /// <param name="value"></param>
        /// <param name="decimalPlacesCount"></param>
        /// <param name="scientificNumCount"></param>
        /// <returns></returns>
        public static string GetScientificNotation(float value, int decimalPlacesCount = 2, int scientificNumCount = 2)
        {
            string result = "0.00E+00";
            if (value < 1)
            {
                result = FormatScientificNotation(value, decimalPlacesCount, scientificNumCount);
            }
            else
            {
                string temp = value.ToString($"F{decimalPlacesCount}");
                int index = temp.IndexOf('.');
                if (index > 1)
                {
                    var sciPart = (index - 1).ToString().PadLeft(scientificNumCount, '0');
                    var numPart = temp.Replace(".", "").Substring(0, 3).PadRight(3, '0');
                    numPart = $"{numPart[0]}.{numPart[1]}{numPart[2]}";
                    result = $"{numPart}E+{sciPart}";
                }
                else
                {
                    result = $"{temp}E+{new string('0', scientificNumCount)}";
                }
            }
            return result;
        }
        /// <summary>
        /// 格式化输出科学计数法
        /// </summary>
        /// <param name="value"></param>
        /// <param name="decimalPlacesCount"></param>
        /// <param name="scientificNumCount"></param>
        /// <returns></returns>
        public static string FormatScientificNotation(float value, int decimalPlacesCount = 2, int scientificNumCount = 2)
        {
            string result = value.ToString($"E{decimalPlacesCount}");
            int index = result.LastIndexOf('-');
            if (index == -1 || index == 0)
            {
                index = result.LastIndexOf('+');
            }
            if (index != -1 && index != 0)
            {
                string numPart = result.Substring(0, index + 1);
                string sciPart = result.Substring(index + 1);
                sciPart = sciPart.TrimStart(ZERO_END_TRIM).PadLeft(scientificNumCount, '0');
                result = $"{numPart}{sciPart}";
            }
            return result;
        }
        /// <summary>
        /// 判断并格式化科学计数法输出
        /// </summary>
        /// <param name="value"></param>
        /// <param name="decimalPlacesCount"></param>
        /// <param name="scientificNumCount"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static string JudgeFormatScientific(string value, int decimalPlacesCount = 2, int scientificNumCount = 2, string defaultValue = "-")
        {
            string result = defaultValue;
            float floatValue = 0f;
            if (!string.IsNullOrWhiteSpace(value) && float.TryParse(value, out floatValue))
            {
                result = GetScientificNotation(floatValue, decimalPlacesCount, scientificNumCount);
            }
            return result;
        }
        /// <summary>
        /// 判断并格式化float
        /// </summary>
        /// <param name="value"></param>
        /// <param name="format"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static string JudgeFormatFloat(string value, string format = "F1", string defaultValue = "-")
        {
            string result = defaultValue;
            float floatValue = 0f;
            if (!string.IsNullOrWhiteSpace(value) && float.TryParse(value, out floatValue))
            {
                result = floatValue.ToString(format);
            }
            return result;
        }
        /// <summary>
        /// 判断并格式化Short
        /// </summary>
        /// <param name="value"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static string JudgeFormatShort(string value, string defaultValue = "-")
        {
            string result = defaultValue;
            short shortValue = 0;
            if (!string.IsNullOrWhiteSpace(value) && short.TryParse(value, out shortValue))
            {
                result = shortValue.ToString();
            }
            return result;
        }
        /// <summary>
        /// 获取完整小数点的字符串
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string DoubleToString(double value)
        {
            string result = "0.0";
            if (value != 0)
            {
                result = value.ToString("F30").TrimEnd(ZERO_END_TRIM);
                if (result.EndsWith("."))
                {
                    result = $"{result}0";
                }
            }
            return result;
        }
        /// <summary>
        /// 获取完整小数点的字符串
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string FloatToString(float value)
        {
            string result = "0.0";
            if (value != 0)
            {
                result = value.ToString("F30").TrimEnd(ZERO_END_TRIM);
                if (result.EndsWith("."))
                {
                    result = $"{result}0";
                }
            }
            return result;
        }
        /// <summary>
        /// 深复制
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T DeepCopy<T>(T obj)
        {
            var json = GetJsonString(obj);
            return JsonConvert.DeserializeObject<T>(json);
        }
    }
}
